package com.hello.sky.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hello.sky.constant.MessageConstant;
import com.hello.sky.context.BaseContext;
import com.hello.sky.exception.SkyException;
import com.hello.sky.mapper.*;
import com.hello.sky.model.dto.*;
import com.hello.sky.model.entity.*;
import com.hello.sky.model.vo.*;
import com.hello.sky.result.PageResult;
import com.hello.sky.service.OrdersService;
import com.hello.sky.util.BaiduGeoUtil;
import com.hello.sky.util.WeChatPayUtil;
import com.hello.sky.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author D
 */
@Slf4j
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {

    @Autowired
    private AddressBookMapper addrMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private OrderDetailMapper orderDetailMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private BaiduGeoUtil baiduGeoUtil;
    @Autowired
    private WebSocketServer webSocketServer;

    @Transactional
    @Override
    public OrderSubmitVO submitOrder(OrdersSubmitDTO orderDto) {
        //校验收获地址
        AddressBook addressBook = addrMapper.selectById(orderDto.getAddressBookId());
        if (addressBook == null) throw SkyException.cast(MessageConstant.ADDRESS_BOOK_IS_NULL);

        //校验购物车
        LambdaQueryWrapper<ShoppingCart> eq = new LambdaQueryWrapper<ShoppingCart>()
                .eq(ShoppingCart::getUserId, BaseContext.getCurrentId());
        List<ShoppingCart> carts = shoppingCartMapper.selectList(eq);
        if (carts == null || carts.size() == 0) throw SkyException.cast(MessageConstant.SHOPPING_CART_IS_NULL);

        //封装数据插入order表
        Orders orders = new Orders();
        BeanUtils.copyProperties(orderDto, orders);
        orders.setPhone(addressBook.getPhone());
        orders.setAddress(addressBook.getDetail());
        orders.setConsignee(addressBook.getConsignee());
        orders.setNumber(String.valueOf(System.currentTimeMillis()));
        orders.setUserId(BaseContext.getCurrentId());
        orders.setStatus(Orders.PENDING_PAYMENT);
        orders.setPayStatus(Orders.UN_PAID);
        orders.setOrderTime(LocalDateTime.now());
        baseMapper.insertOrder(orders);

        //httpClient检查用户的位置是否支持配送
        Integer distance = baiduGeoUtil.computeGeoDistance(addressBook.getProvinceName() + addressBook.getCityName() + addressBook.getDistrictName() + addressBook.getDetail());
        if (distance > 5000){
            BigDecimal bigDecimal = new BigDecimal(distance);
            String s = bigDecimal.divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP).toString() + "km";
            throw SkyException.cast("超出配送范围5km,实际距离" + s);
        }

        //封装数据插入roders_detail表
        List<OrderDetail> orderDetailList = carts.stream().map(cart -> {
            OrderDetail orderDetail = new OrderDetail();
            BeanUtils.copyProperties(cart, orderDetail);
            orderDetail.setOrderId(orders.getId());
            return orderDetail;
        }).collect(Collectors.toList());
        orderDetailMapper.insertBatch(orderDetailList);

        //删除购物车的数据
        List<Long> ids = carts.stream().map(ShoppingCart::getId).toList();
        shoppingCartMapper.deleteBatchIds(ids);

        //封装返回数据
        OrderSubmitVO orderSubmitVO = new OrderSubmitVO();
        orderSubmitVO.setId(orders.getId());
        orderSubmitVO.setOrderAmount(orders.getAmount());
        orderSubmitVO.setOrderNumber(orders.getNumber());
        orderSubmitVO.setOrderTime(orders.getOrderTime());
        return orderSubmitVO;
    }

    /**
     * 订单支付
     *
     * @param ordersPaymentDTO
     * @return
     */
    public OrderPaymentVO payment(OrdersPaymentDTO ordersPaymentDTO) throws Exception {
/*        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口，生成预支付交易单
        JSONObject jsonObject = weChatPayUtil.pay(
                ordersPaymentDTO.getOrderNumber(), //商户订单号
                new BigDecimal(0.01), //支付金额，单位 元
                "苍穹外卖订单", //商品描述
                user.getOpenid() //微信用户的openid
        );

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw SkyException.cast("该订单已支付");
        }

        OrderPaymentVO vo = jsonObject.toJavaObject(OrderPaymentVO.class);
        vo.setPackageStr(jsonObject.getString("package"));*/

        //没有真实的小程序商户id，因此上面的代码直接跳过
        //这里假设支付成功，微信支付调用成功逻辑，进行业务处理，修改订单状态、来单提醒
        paySuccess(ordersPaymentDTO.getOrderNumber());

        return new OrderPaymentVO();
    }

    /**
     * 支付成功，修改订单状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();

        // 根据订单号查询当前用户的订单
        Orders ordersDB = ordersMapper.getByNumberAndUserId(outTradeNo, userId);

        // 根据订单id更新订单的状态、支付方式、支付状态、结账时间
        Orders orders = Orders.builder()
                .id(ordersDB.getId())
                .status(Orders.TO_BE_CONFIRMED)
                .payStatus(Orders.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();

        Map map = new HashMap();
        map.put("type", 1);//消息类型，1表示来单提醒
        map.put("orderId", orders.getId());
        map.put("content", "订单号：" + outTradeNo);

        //通过WebSocket实现来单提醒，向客户端浏览器推送消息
        webSocketServer.sendToAllClient(JSON.toJSONString(map));

        ordersMapper.update(orders);
    }

    @Override
    public PageResult historyOrdersPage(OrdersPageQueryDTO dto) {
        Long userId = BaseContext.getCurrentId();
        //分页条件查询
        dto.setUserId(BaseContext.getCurrentId());
        IPage<OrderVO> orderHistoryVos = baseMapper.selectOrderWithDetailPage(dto, new Page<>(dto.getPage(), dto.getPageSize()));

        return new PageResult(orderHistoryVos.getTotal(), orderHistoryVos.getRecords());
    }

    @Override
    public OrderVO historyOrdersByOrderId(Long orderId) {
        return baseMapper.selectOrderWithDetailByOrderId(orderId);
    }

    /**
     * 根据业务流程图，订单取消操作能取消状态为待支付1、待接单2、已接单(待派送)3、派送中4、已完成的订单5
     * 用户可以在订单为1、2状态取消订单，状态3、4、5需要用户电话练习商家，让商家进行取消订单操作
     * 商家可以在2、3、4、5状态取消订单
     * 待支付1进行取消订单不需要修改支付状态
     * @param orderId
     */
    @Transactional
    @Override
    public void userCancelByOrderId(Long orderId) {
        Orders orders = baseMapper.selectById(orderId);

        //订单是否存在
        if (orders == null) throw SkyException.cast(MessageConstant.ORDER_NOT_FOUND);

        //用户只能取消1，2状态以下也就是待支付和待接单状态的订单,状态不对直接报错
        if (orders.getStatus() > Orders.TO_BE_CONFIRMED){
            throw SkyException.cast(MessageConstant.ORDER_STATUS_ERROR);
        }

        //订单状态更改为已取消，支付状态更改为退款、填充取消时间
        orders.setStatus(Orders.CANCELLED);

        //状态为待接单2才需要更改支付状态
        if (orders.getStatus() == Orders.TO_BE_CONFIRMED)orders.setPayStatus(Orders.REFUND);
        orders.setCancelTime(LocalDateTime.now());

        //更新订单表
        baseMapper.cancelUpdate(orders);
    }

    /**
     * 先删原来的，在把订单明细的加到购物车
     * @param id
     */
    @Transactional
    @Override
    public void repetition(Long id) {
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new LambdaQueryWrapper<OrderDetail>().eq(OrderDetail::getOrderId, id));
        //查到该订单的用户的id
        Long userId = baseMapper.selectById(id).getUserId();
        //先清除该用户原来的购物车
        shoppingCartMapper.delBatchByUserId(userId);
        //再将该订单的detaill转换为shoppingcart插入到购物车表
        List<ShoppingCart> cartList = orderDetailList.stream().map(detail -> {
            ShoppingCart shoppingCart = new ShoppingCart();
            BeanUtils.copyProperties(detail, shoppingCart);
            shoppingCart.setUserId(userId);
            return shoppingCart;
        }).toList();
     shoppingCartMapper.insertBatch(cartList);
    }

    /**
     * 商家条件查询所有订单
     * @param dto
     * @return
     */
    @Override
    public PageResult conditionSearchPage(OrdersPageQueryDTO dto) {
        IPage<OrderVO> page = selectOrderWithDetailPage(dto);

        return new PageResult(page.getTotal(), page.getRecords());
    }

    private IPage<OrderVO> selectOrderWithDetailPage(OrdersPageQueryDTO dto) {

        IPage<OrderVO> page = baseMapper.selectOrderWithDetailPage(dto, new Page<OrderVO>(dto.getPage(), dto.getPageSize()));
        List<OrderVO> orderHistoryVos = page.getRecords();
        //还要为每个订单封装orderDishes信息
        List<Long> ids = orderHistoryVos.stream().map(Orders::getId).toList();
        if (ids == null || ids.size() == 0) return page;
        Map<Long, OrderVO> dishesMap = baseMapper.selectDishesByOrderIds(ids);
        orderHistoryVos.forEach(vo -> {
            String orderDishes = dishesMap.get(vo.getId()).getOrderDishes();
            vo.setOrderDishes(orderDishes);
        });
        return page;
    }

    @Override
    public void accept(Orders orders) {
        Orders ordersData = baseMapper.selectById(orders.getId());
        //订单非空校验
        if (ordersData == null) throw SkyException.cast(MessageConstant.ORDER_NOT_FOUND);
        //订单状态检验
        if (ordersData.getStatus() != Orders.TO_BE_CONFIRMED) throw SkyException.cast(MessageConstant.ORDER_STATUS_ERROR);

        //修改订单状态
        ordersData.setStatus(Orders.CONFIRMED);
        //更新数据库
        baseMapper.updateConfirm(ordersData);
    }

    /**
     * 拒单操作只能在订单状态为待接单2的情况下进行
     * @param dto
     */
    @Override
    public void rejection(OrdersRejectionDTO dto) {
        Orders orders = baseMapper.selectById(dto.getId());
        //只有状态为待接单2的才能被拒单
        if (orders.getStatus() != Orders.TO_BE_CONFIRMED) throw SkyException.cast(MessageConstant.ORDER_STATUS_ERROR);

        //退款并更新订单支付状态
        orders.setPayStatus(Orders.REFUND);

        //更新订单状态
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelTime(LocalDateTime.now());
        orders.setCancelReason(dto.getRejectionReason());
        baseMapper.update(orders);
    }

    /**
     * 根据业务流程图，订单取消操作能取消状态为待支付1、待接单2、已接单(待派送)3、派送中4、已完成的订单5
     * 用户可以在订单为1、2状态取消订单，状态3、4、5需要用户电话练习商家，让商家进行取消订单操作
     * 商家可以在2状态拒单，3、4、5状态取消订单
     * 待支付1进行取消订单不需要修改支付状态
     * @param dto
     */
    @Override
    public void adminCancel(OrdersCancelDTO dto) {
        Orders orders = baseMapper.selectById(dto.getId());
        if (orders == null) throw SkyException.cast(MessageConstant.ORDER_NOT_FOUND);

        //状态只能是2、3、4、5
        if (orders.getStatus() == Orders.PENDING_PAYMENT || orders.getStatus() == Orders.CANCELLED) throw SkyException.cast(MessageConstant.ORDER_STATUS_ERROR);

        //退款
        orders.setPayStatus(Orders.REFUND);

        //修改数据库数据
        orders.setStatus(Orders.CANCELLED);
        orders.setCancelTime(LocalDateTime.now());
        orders.setCancelReason(dto.getCancelReason());
        updateById(orders);
    }

    /**
     * 出餐完成，商家开始派送
     * @param orderId
     */
    @Override
    public void delivery(Long orderId) {
        Orders orders = baseMapper.selectById(orderId);
        if (orders == null) throw SkyException.cast(MessageConstant.ORDER_NOT_FOUND);

        //状态只能是待派送3
        if (orders.getStatus() != Orders.CONFIRMED) throw SkyException.cast(MessageConstant.ORDER_STATUS_ERROR);

        //修改订单状态
        orders.setStatus(Orders.DELIVERY_IN_PROGRESS);
        updateById(orders);
    }

    @Override
    public void complete(Long orderId) {
        Orders orders = baseMapper.selectById(orderId);
        if (orders == null) throw SkyException.cast(MessageConstant.ORDER_NOT_FOUND);

        //状态只能是派送中4
        if (orders.getStatus() != Orders.DELIVERY_IN_PROGRESS) throw SkyException.cast(MessageConstant.ORDER_STATUS_ERROR);

        //修改订单状态、送达时间
        orders.setStatus(Orders.COMPLETED);
        orders.setDeliveryTime(LocalDateTime.now());

        updateById(orders);
    }

    @Override
    public OrderVO orderDetail(Long id) {

        return baseMapper.selectOrderWithDetailByOrderId(id);
    }

    @Override
    public void reminder(Long id) {
        HashMap<String, String> map = new HashMap<>();
        map.put("type", "2");
        map.put("orderId", id.toString());
        map.put("content", "订单号：" + id.toString() + " 用户客户催单");
        webSocketServer.sendToAllClient(JSON.toJSONString(map));
    }

    @Override
    public OrderStatisticsVO statistics() {
        OrderStatisticsVO vo = new OrderStatisticsVO();
        LocalDateTime localDateTime = LocalDateTime.now();
        vo.setToBeConfirmed(ordersMapper.countByStatusAndSingalDate(localDateTime, Orders.TO_BE_CONFIRMED).size());
        vo.setConfirmed(ordersMapper.countByStatusAndSingalDate(localDateTime, Orders.CONFIRMED).size());
        vo.setDeliveryInProgress(ordersMapper.countByStatusAndSingalDate(localDateTime, Orders.DELIVERY_IN_PROGRESS).size());
        return vo;
    }
}
